package com.orm.proxy;


import com.orm.mapping.MapperStatement;
import com.orm.session.DefaultSqlSession;
import com.orm.session.SqlSession;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 创建代理的 Mapper InvocationHandler 对象，但实际sql 的执行就交给 SqlSession 的执行器的
 */
@Slf4j
public class MapperProxy implements InvocationHandler {
	private SqlSession sqlSession;
	private String namespace;
	
	private final String SELECT = "select";
	private final String UPDATE = "update";
	private final String DELETE = "delete";
	private final String INSERT = "insert";
	
	public MapperProxy(SqlSession sqlSession,String namespace) {
		this.sqlSession = sqlSession;
		this.namespace = namespace;
	}
	
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// Class<?> declaringClass = method.getDeclaringClass();
		// if(declaringClass.equals(Object.class)){
		// 	return method.invoke( this,args);
		// }
		
		// 过滤掉 Object 类方法
		if(method.getDeclaringClass().equals(Object.class)){
			return method.invoke( this,args);
		}
		
		// 为了支持BaseMapper<T> 里面的方法 这样改造了
		
		// String methodFullName = declaringClass.getName() + "." + method.getName();   // 用类全名.方法名 来检查下
		String methodFullName = namespace + "." + method.getName();   // 用类全名.方法名 来检查下
		
		
		MapperStatement mapperStatement = sqlSession.getConfiguration().getMapperStatements().get(methodFullName);
		
		if(mapperStatement == null){
			log.error("该=方法没有绑定sql语句，无法执行 -> {}()", methodFullName);
			throw new RuntimeException("方法没有关联sql");
		}
		
		Object result = null;
		String sqlType = mapperStatement.getSqlType();
		switch (sqlType){
			case INSERT:
				result = sqlSession.insert(mapperStatement,args);
				break;
			case UPDATE:
				result = sqlSession.update(mapperStatement, args);
				break;
			case DELETE:
				result = sqlSession.update(mapperStatement, args);
				break;
			case SELECT:
				if(mapperStatement.isReturnVoid()){
					sqlSession.selectList(mapperStatement, args);
					result = null;                               // 返回空的，真不知道到底选择什么方法处理
				}else if(mapperStatement.isReturnCount()){
					result = sqlSession.selectCount(mapperStatement,args);
				}else if(mapperStatement.isReturnOne()){
					result = sqlSession.selectOne(mapperStatement,args);
				}else if(mapperStatement.isReturnMany()){
					result = sqlSession.selectList(mapperStatement,args);
				}
				break;
			default:
				log.error("不支持的sql语句类型:{}", sqlType);
				break;
		}
		return result;
	}
	
	
	/*
	 * 下面是 重写 Object 类的方法,因为代理对象的所有方法，包括toString() 都会到 InvocationHandler 这里来，对于 Object 类的方法必须提供一个处理方法
	 */
	@Override
	public int hashCode() {
		return super.hashCode();
	}
	
	@Override
	public boolean equals(Object obj) {
		return super.equals(obj);
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
	
	@Override
	public String toString() {
		return super.toString();
	}
}
